<!--
 * @Author: weidewei
 * @Date: 2025-10-31 09:21:27
 * @LastEditors: weidewei
 * @LastEditTime: 2025-10-31 11:11:08
 * @Description: 
 * @FilePath: \2025-front-face\review-knowledge\20251030\复习this指向.html
-->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <button id="btn">点击</button>
    <button id="myBtn1">点击1</button>
    <button id="myBtn2">点击2</button>
  </body>
</html>
<script>
  // ​题目 1​​（严格模式 + 默认绑定）
  "use strict";
  function test() {
    console.log(this); // 问题1：输出什么？ 全局 错 答案：undefined 严格模式下this禁止指向全局对象
  }
  test();

  //   题目 2​​（嵌套对象的方法调用）
  const obj1 = {
    name: "Obj1",
    obj2: {
      name: "Obj2",
      sayName: function () {
        console.log(this.name); // 问题2：输出什么？Obj2
      },
    },
  };
  obj1.obj2.sayName();

  //   题目 3​​（call 绑定后赋值调用）
  function greet() {
    console.log(this.name); // 问题3：输出什么？A A 错 答案： A 报错 boundGreet is not a function
    // return function () {
    //     console.log('thisname',this.name)
    // }
  }
  const personA = { name: "A" };
  const personB = { name: "B" };

  const boundGreet = greet.call(personA); // 先绑定到 personA
  // boundGreet(); // 单独调用这个函数

  //   题目 4​​（对象字面量中的箭头函数）

  const obj = {
    name: "Bob",
    sayThis: () => console.log(this), // 箭头函数继承外层 this 箭头函数没有自己的this
  };
  obj.sayThis(); // 问题4：this 指向什么？全局

  //   题目 5​​（构造函数中的箭头函数方法）
  function Dog(name) {
    this.name = name;
    // 箭头函数绑定到当前实例
    this.bark = () => console.log(`${this.name} 汪汪！`);
  }
  const myDog = new Dog("小白");
  const bark = myDog.bark;
  bark(); // 问题5：输出什么？（会不会报错？）会报错 错 答案：小白 汪汪

  //   题目 6​​（DOM 事件 - 箭头函数处理函数）浏览器环境，按钮 <button id="btn">点击</button>，执行
  //   document.getElementById("btn").addEventListener("click", () => {
  //     console.log(this.tagName); // 问题6：输出什么？（和普通函数有何区别？）undefined 箭头函数没有自己的this，要往上一层作用域去找
  //   });
  document.getElementById("btn").addEventListener("click", function () {
    console.log(this.tagName); // 问题6：输出什么？（和普通函数有何区别？）BUTTON
  });

  //   题目 7​​（Promise.then 中的箭头函数）
  const obj7 = {
    name: "Charlie",
    fetchData: function () {
      Promise.resolve().then(() => {
        console.log(this.name); // 问题7：输出什么？Charlie
      });
    },
  };
  obj7.fetchData();

  //   题目 8​​（ES6 类的静态方法）
  class MathUtils {
    static add(a, b) {
      console.log(this === MathUtils); // 问题8：输出 true 还是 false？false 错 答案：true 静态方法属于类本身，调用时this指向类​​。
    }
  }
  MathUtils.add(); // 静态方法调用

  //   题目 9​​（多层对象链调用）
  const a = {
    name: "A",
    b: {
      name: "B",
      c: {
        name: "C",
        say: function () {
          console.log(this.name); // 问题9：输出什么？C
        },
      },
    },
  };
  a.b.c.say();

  //   题目 10​​（方法赋值给其他对象）
  const obj10 = {
    name: "Obj1",
    greet: function () {
      console.log(`Hello from ${this.name}`);
    },
  };
  const obj9 = {
    name: "Obj2",
  };
  obj9.greet = obj10.greet; // 把 obj1 的方法赋值给 obj2
  obj9.greet(); // 问题10：输出什么？Hello from Obj2

  console.log("================================");
  // 巩固题目
  //   ​题目 1​​（严格模式 + 默认绑定）
  //   ("use strict");
  //   const obj12 = {
  //     name: "Alice",
  //     sayHi: function () {
  //       console.log(this.name); // 报错
  //     },
  //   };
  //   const hi = obj12.sayHi;
  //   hi(); // 输出什么？

  //   题目 2​​（call的临时性 vs 函数本身的this）
  function showName() {
    console.log(this.name);
  }
  const person1 = { name: "Bob" };
  const person2 = { name: "Charlie" };

  showName.call(person1); // 第一次调用，输出什么？Bob
  showName.call(person2); // 第二次调用，输出什么？Charlie
  // 函数本身的 this 还是 person1 吗？不是

  //   题目 3​​（箭头函数的词法绑定）
  const outerObj = {
    name: "Outer",
    innerFunc: () => {
      console.log(this.name); // 箭头函数定义在 outerObj 外部吗？undefined
    },
  };
  outerObj.innerFunc(); // 输出什么？undefined

  //   ​题目 4​​（事件处理函数 - 普通函数 vs 箭头函数）
  const handler = function () {
    console.log("普通函数:", this.tagName);
  };
  const arrowHandler = () => {
    console.log("箭头函数:", this.tagName);
  };

  document.getElementById("myBtn1").addEventListener("click", handler);
  document.getElementById("myBtn2").addEventListener("click", arrowHandler);

  //   题目 5​​（类实例方法 vs 静态方法）
  class Calculator {
    static PI = 3.14;
    add(a, b) {
      console.log(this === instance); // 实例方法调用时，this 是实例吗？true
    }
    static multiply(a, b) {
      console.log(this.PI); // 静态方法调用时，this 指向哪里？3.14
    }
  }

  const instance = new Calculator();
  instance.add(1, 2); // 输出什么？
  Calculator.multiply(2, 3); // 输出什么？

  //   题目 6​​（方法赋值给其他对象）
  const cat = {
    name: "Tom",
    greet: function () {
      console.log(`Meow, I'm ${this.name}`);
    },
  };
  const dog = {
    name: "Jerry",
  };
  dog.greet = cat.greet; // 把 cat 的方法赋值给 dog
  dog.greet(); // 输出什么？Meow, I'm Jerry

  //   题目 7​​（构造函数中的箭头函数方法）
  function Bird(name) {
    this.name = name;
    this.sing = () => console.log(`${this.name} 唱歌！`);
  }
  const tweety = new Bird("Tweety");
  const sing = tweety.sing;
  sing(); // 输出什么？（会不会报错？）Tweety 唱歌！

  //   题目 8​​（多层对象 + 箭头函数）
  const globalObj = {
    name: "Global",
    inner: {
      name: "Inner",
      //   say: () => console.log(this.name), // 箭头函数定义在 globalObj 内部吗？
      say: function () {
        console.log("name", this.name);
      },
    },
  };
  globalObj.inner.say(); // 输出什么？Global 错 答案：undefined 普通对象（{}）​​不会创建作用域​​

  //   题目：嵌套对象的方法调用对比​
  const globalObj1 = {
    name: "Global",
    inner: {
      name: "Inner",
      // 普通函数方法
      regularSay: function () {
        console.log(`普通函数：${this.name}`);
      },
      // 箭头函数方法
      arrowSay: () => {
        console.log(`箭头函数：${this.name}`);
      },
    },
  };

  // 场景1：直接作为内层对象的方法调用
  globalObj1.inner.regularSay(); // 输出什么？Inner
  globalObj1.inner.arrowSay(); // 输出什么？undefined

  // 场景2：将方法赋值给全局变量后单独调用
  const tempRegular = globalObj1.inner.regularSay;
  const tempArrow = globalObj1.inner.arrowSay;
  tempRegular(); // 输出什么？undefined
  tempArrow(); // 输出什么？undefined
</script>
